<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <script src="./vue.js"></script>
    <!-- <script src="./axios.js"></script> -->
    <style>
        #left,
        #right {
            width: 1000px;
            height: 600px;
            border: 1px solid red;
            margin-bottom: 10px;
            overflow: auto;
        }
    </style>
</head>

<body>
    <div id="box">
        <button @click='setHTMLWithScript'>点击运行</button>
        <br>
        <textarea id="left" v-model="htmlScript">{{htmlScript}}</textarea>
        <div id="right" v-html="screen">{{screen}}</div>
    </div>
</body>
<script>
    let vm = new Vue({
        el: box,
        data() {
            return {
                htmlScript: null,
                screen: null,
            }
        },
        methods: {
            runScript(script) {
                return new Promise((reslove, rejected) => {
                    // 直接 document.head.appendChild(script) 是不会生效的，需要重新创建一个
                    const newScript = document.createElement('script');
                    // 获取 inline script
                    newScript.innerHTML = script.innerHTML;
                    // 存在 src 属性的话
                    const src = script.getAttribute('src');
                    if (src) newScript.setAttribute('src', src);

                    // script 加载完成和错误处理
                    newScript.onload = () => reslove();
                    newScript.onerror = err => rejected();
                    document.head.appendChild(newScript);
                    document.head.removeChild(newScript);
                    if (!src) {
                        // 如果是 inline script 执行是同步的
                        reslove();
                    }
                })
            },
            setHTMLWithScript() {
                const
                    container = this.$el,
                    rawHTML = html,
                    scripts = container.querySelectorAll('script');

                return Array.prototype.slice.apply(scripts).reduce((chain, script) => {
                    return chain.then(() => this.runScript(script));
                }, Promise.resolve());
            }
        },
    })

    vm.$watch("htmlScript", function(newVal, oldVal) {
        vm.screen = newVal
    })

    let html = null;
    html =
        '<!DOCTYPE html>\n' +
        '<html lang="en">\n' +
        '<head>\n' +
        '   <meta charset="UTF-8">\n' +
        '   <title>Document</title>\n' +
        '</head>\n' +
        '<body>\n' +
        '</body>\n' +
        '</html>'
    vm.htmlScript = html;
</script>

</html>